home *** CD-ROM | disk | FTP | other *** search
/ The Arsenal Files 8 / The Arsenal Files Collection #8 (Arsenal Computer) (1996).ISO / g_quake / server~1.zip / _DRONE.QC < prev    next >
Text File  |  1996-10-04  |  18KB  |  601 lines

  1. /*
  2. **
  3. ** _drone.qc (Drone Code, 1.0)
  4. **
  5. ** Copyright (C) 1996 Johannes Plass
  6. ** 
  7. ** This program is free software; you can redistribute it and/or modify
  8. ** it under the terms of the GNU General Public License as published by
  9. ** the Free Software Foundation; either version 2 of the License, or
  10. ** (at your option) any later version.
  11. ** 
  12. ** This program is distributed in the hope that it will be useful,
  13. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. ** GNU General Public License for more details.
  16. **
  17. ** You should have received a copy of the GNU General Public License
  18. ** along with this program; if not, write to the Free Software
  19. ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. ** 
  21. ** Author:   Johannes Plass (plass@dipmza.physik.uni-mainz.de)
  22. **
  23. */
  24.  
  25. void(entity player) DroneInfo =
  26. {
  27.   if (!USE_MODULE_DRONE) return;
  28.  
  29.               // 123456789#123456789#123456789#12345678
  30.   sprint(player,"£");
  31.   sprint(player," Drone");
  32.   sprint(player,        " provides homing missiles.\n");
  33.   sprint(player,"  Type 'help-drone' for help.\n");
  34. };
  35.  
  36. void(entity player) DroneInit =
  37. {
  38.   if (!USE_MODULE_DRONE) return;
  39.   stuffcmd(player,"alias help-drone \"impulse 215\";\n");
  40. };
  41.  
  42. void(entity player) DroneHelp =
  43. {
  44.   if (!USE_MODULE_DRONE) return;
  45.   
  46.                // 123456789#123456789#123456789#12345678
  47.   sprint(player,"Drone:");
  48.   sprint(player,       " provides homing missiles.\n");
  49.   sprint(player,"To launch a drone double-select the\n");
  50.   sprint(player,"grenade launcher, then press fire.\n");
  51.   sprint(player,"The silver key is lit if the grenade\n");
  52.   sprint(player,"launcher fires drones.\n");
  53.   sprint(player,"The gold key is lit if you are\n");
  54.   sprint(player,"targeted by a drone.\n");
  55.   sprint(player,"Flying drones can be shot down.\n");
  56. };
  57.  
  58. void(entity player) DroneActiveMessage =
  59. {
  60.   if (!USE_MODULE_DRONE) return;
  61.   
  62.               // 123456789#123456789#123456789#12345678
  63.   sprint(player,"  Drone         (help-drone)\n");
  64. };
  65.  
  66. //========================================================================
  67. //   DroneToggleWeapon
  68. //========================================================================
  69.  
  70. void(entity player) DroneToggleWeapon =
  71. {
  72.   if (!USE_MODULE_DRONE) return;
  73.   
  74.   if (player.modules_weapon & MODULES_WEAPON_DRONE) {
  75.     player.modules_weapon = player.modules_weapon - MODULES_WEAPON_DRONE;
  76.     player.items = player.items - (player.items & IT_KEY1);
  77.   } else {
  78.     if ((player.weapon == IT_GRENADE_LAUNCHER) && (player.ammo_rockets >= 1)) {
  79.       player.modules_weapon = player.modules_weapon | MODULES_WEAPON_DRONE;
  80.       player.items = player.items | IT_KEY1;
  81.     }
  82.   }
  83. };
  84.  
  85. //========================================================================
  86. //   DroneResetWeapon
  87. //========================================================================
  88.  
  89. void(entity player) DroneResetWeapon =
  90. {
  91.   if (!USE_MODULE_DRONE) return;
  92.   if (player.modules_weapon & MODULES_WEAPON_DRONE) {
  93.     player.modules_weapon = player.modules_weapon - MODULES_WEAPON_DRONE;
  94.     player.items = player.items - (player.items & IT_KEY1);
  95.   }
  96. };
  97.  
  98. //========================================================================
  99. //   DroneThreat
  100. //========================================================================
  101.  
  102. void(entity player,float threat) DroneThreat =
  103. {
  104.   if (threat) player.items = player.items | IT_KEY2;
  105.   else        player.items = player.items - (player.items & IT_KEY2);
  106. };
  107.  
  108. //========================================================================
  109. //   DroneRemoveFromQueue
  110. //========================================================================
  111.  
  112. void(entity player,entity drone) DroneRemoveFromQueue =
  113. {
  114.   //dprint("DroneRemoveFromQueue\n");
  115.   
  116.   if (!drone.drone_in_queue) return;
  117.   
  118.   if (player.drone_1 == drone) {
  119.     player.drone_1 = world;
  120.     player.drone_count = player.drone_count - (player.drone_count & 1);
  121.   }
  122.   else if (player.drone_2 == drone) {
  123.     player.drone_2 = world;
  124.     player.drone_count = player.drone_count - (player.drone_count & 2);
  125.   }
  126.   else if (player.drone_4 == drone) {
  127.     player.drone_4 = world;
  128.     player.drone_count = player.drone_count - (player.drone_count & 4);
  129.   }
  130.   else if (player.drone_8 == drone) {
  131.     player.drone_8 = world;
  132.     player.drone_count = player.drone_count - (player.drone_count & 8);
  133.    }
  134.   drone.drone_in_queue = 0;
  135. };
  136.  
  137. //========================================================================
  138. //   DroneAddToQueue
  139. //========================================================================
  140.  
  141. void(entity player,entity drone) DroneAddToQueue =
  142. {
  143.   //dprint("DroneAddToQueue\n");
  144.  
  145.   if      (!(player.drone_count & 1)) {
  146.     player.drone_1 = drone;
  147.     player.drone_count = player.drone_count | 1;
  148.    }
  149.   else if (!(player.drone_count & 2)) {
  150.     player.drone_2 = drone;
  151.     player.drone_count = player.drone_count | 2;
  152.   }
  153.   else if (!(player.drone_count & 4)) {
  154.     player.drone_4 = drone;
  155.     player.drone_count = player.drone_count | 4;
  156.   }
  157.   else if (!(player.drone_count & 8)) {
  158.     player.drone_8 = drone;
  159.     player.drone_count = player.drone_count | 8;
  160.   }
  161.   drone.drone_in_queue = 1;
  162. };
  163.  
  164. //========================================================================
  165. //   DroneRemoveDrone
  166. //========================================================================
  167.  
  168. void(entity player) DroneRemoveDrone =
  169. {
  170.   local entity m;
  171.   local float t;
  172.  
  173.   //dprint("DroneRemoveDrone\n");
  174.  
  175.   if (player.drone_count & 15 != 15) return;
  176.   t = time+10;
  177.   m = world;
  178.   if (player.drone_count &  1) 
  179.     { if (player.drone_1.ltime  < t) { m = player.drone_1;  t = player.drone_1.ltime;  }}
  180.   if (player.drone_count &  2) 
  181.     { if (player.drone_2.ltime  < t) { m = player.drone_2;  t = player.drone_2.ltime;  }}
  182.   if (player.drone_count &  4) 
  183.     { if (player.drone_4.ltime  < t) { m = player.drone_4;  t = player.drone_4.ltime;  }}
  184.    if (player.drone_count &  8) 
  185.     { if (player.drone_8.ltime  < t) { m = player.drone_8;  t = player.drone_8.ltime;  }}
  186.   
  187.   if (m!= world) {
  188.     //dprint("killing drone\n"); 
  189.     DroneRemoveFromQueue(m.drone_owner,m);
  190.     m.nextthink = time+0.01;
  191.     m.touch     = SUB_Null;
  192.     m.think     = DroneDie;
  193.   }
  194. };
  195.  
  196. //========================================================================
  197. //   DroneFire
  198. //========================================================================
  199.  
  200. void(entity drone) DroneFire =
  201. {
  202.   //dprint("DroneFire\n");
  203.   
  204.   DroneRemoveDrone(self);
  205.   self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
  206.   
  207.   self.punchangle_x = -2;
  208.   makevectors(self.v_angle);
  209.   
  210.   drone                  = spawn();
  211.   drone.classname        = "drone";
  212.   drone.owner            = self;
  213.   drone.drone_owner      = self;
  214.   drone.movetype         = MOVETYPE_FLY;
  215.   drone.solid            = SOLID_BBOX;
  216.   drone.velocity         = aim(self,DRONE_VELOCITY_START);
  217.   drone.velocity         = drone.velocity * DRONE_VELOCITY_START;
  218.   drone.origin           = self.origin + v_forward*12 + '0 0 16';
  219.   drone.modules_weapon   = MODULES_WEAPON_DRONE;
  220.   drone.angles           = vectoangles(drone.velocity);
  221.   drone.touch            = DroneTouch;
  222.   drone.ltime            = time;
  223.   drone.nextthink        = time + DRONE_THINK_FIRSTTIME;
  224.   drone.think            = DroneThink;
  225.   drone.avelocity        = '300 300 300';
  226.   drone.effects          = drone.effects | EF_DIMLIGHT;
  227.   drone.health           = 20;
  228.   drone.takedamage       = DAMAGE_AIM;
  229.   drone.th_die           = DroneDie;
  230.   
  231.   drone.enemy = self;
  232.   drone.drone_target_vector   = self.origin;
  233.   drone.drone_target_vector_z = drone.drone_target_vector_z + DRONE_TARGET_OFFSET_Z;
  234.   drone.drone_target_velocity = self.velocity;
  235.   drone.drone_set_target_vector_time = time - 10;
  236.   DroneFindTarget(drone);
  237.   DroneAddToQueue(self,drone);
  238.   DroneThreat(drone.enemy,TRUE);
  239.   
  240.   setmodel (drone, "progs/v_spike.mdl");
  241.   setsize (drone, '0 0 0', '0 0 0');        
  242.   setorigin (drone, drone.origin);        
  243.   sound (self,  CHAN_WEAPON, drone_launch_sound_1, 1, ATTN_NORM);
  244.   sound (drone, CHAN_WEAPON, drone_launch_sound_2, 1, ATTN_NORM);
  245.   drone.drone_sound_time = time - 0.3;
  246. };
  247.  
  248. //========================================================================
  249. //   DroneTouch
  250. //========================================================================
  251.  
  252. float DRONE_DAMAGE_RADIUS = 70;
  253.  
  254. void() DroneTouch = 
  255. {
  256.   local float    d,db,r;
  257.   local entity  e;
  258.   
  259.   //dprint("DroneTouch\n");
  260.   //dprint(other.classname); dprint("\n");
  261.  
  262.   if (pointcontents(self.origin) == CONTENT_SKY) {
  263.     DroneThreat(self.enemy,FALSE);
  264.     remove(self);
  265.     return;
  266.   }
  267.   
  268.   if (other.solid == SOLID_BSP) {
  269.     //dprint("wall collision\n");
  270.     //dprint(vtos(self.velocity)); dprint("\n");
  271.     if (checkbottom(self)) {
  272.       //dprint("on floor\n");
  273.       if (self.drone_bounced) self.origin_z = self.origin_z + 8;
  274.       if (!self.drone_firstthink) self.nextthink = time + 0.1;
  275.     }
  276.     if (time > self.drone_bounce_sound_time + 0.6) {
  277.       //dprint("drone receives damage\n");
  278.       sound (self, CHAN_WEAPON, "weapons/bounce.wav", 0.6, ATTN_NORM);
  279.       self.drone_bounce_sound_time = time;
  280.       self.drone_sound_time = time - 0.4;
  281.       if (self.health > 0) T_Damage (self, world, world, 3);
  282.     }
  283.     self.drone_bounce_time = time;
  284.     self.drone_bounced = 1;
  285.     setsize (self, '-0 -0 -0', '0 0 0');
  286.     return;
  287.   }
  288.   else if (other.solid == SOLID_BBOX) {
  289.     if (other.classname == "drone" && self.drone_count >= 0) {
  290.       //dprint("bounce against drone\n");
  291.       if (time > self.drone_bounce_sound_time + 0.6) {
  292.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 0.8, ATTN_NORM);
  293.     self.drone_bounce_sound_time = time;
  294.     self.drone_sound_time = time;
  295.     if (self.health > 0) {
  296.       d = 6;
  297.       if (self.drone_owner == other.drone_owner) d = 3;
  298.       T_Damage (self, world, world, d); 
  299.     }
  300.       }
  301.       return;
  302.     }
  303.     else if (other.classname == "grenade") {
  304.       sound (self, CHAN_WEAPON, "weapons/bounce.wav", 0.6, ATTN_NORM);
  305.       self.drone_sound_time = time;
  306.       if (self.health > 0) T_Damage (self, world, world, 5);
  307.       return;
  308.     }
  309.     else if (other.classname == "spike") {
  310.       sound (self, CHAN_WEAPON, "weapons/bounce.wav", 0.6, ATTN_NORM);
  311.       self.drone_sound_time = time;
  312.       if (self.health > 0) T_Damage (self, world, world, 6);
  313.       return;
  314.     }
  315.   }
  316.  
  317.   self.think      = DroneDie;    // be on the 
  318.   self.nextthink  = time +3;     // safe side
  319.   self.owner = self.drone_owner;
  320.  
  321.   DroneThreat(self.enemy,FALSE);
  322.   DroneRemoveFromQueue(self.drone_owner,self);
  323.  
  324.   e = findradius(self.origin, DRONE_DAMAGE_RADIUS);
  325.   while (e) {
  326.     if (e.takedamage == DAMAGE_AIM) {
  327.       if (e.health > 0) {
  328.     if (e != self) {
  329.       r = random();
  330.       db = 40 + r*5;
  331.       d = vlen(e.origin + '0 0 16' - self.origin);
  332.           if      (d < DRONE_DAMAGE_RADIUS - 1.2*db) d = db;
  333.           else if (d < DRONE_DAMAGE_RADIUS) d = (DRONE_DAMAGE_RADIUS-d)*0.83;
  334.           else d = 0;
  335.       if (d > 0) {
  336.         if (e.classname == "drone") {
  337.           if (e.drone_owner == self.drone_owner) d = d*0.4;
  338.           e.health = e.health - d;
  339.           if (e.health <= 0) {
  340.         e.think = DroneDie;
  341.         e.nextthink = time + 0.01;
  342.           }
  343.         } else {
  344.           T_Damage (e, self, self.drone_owner, d);
  345.           if (r > 0.95) {                //#jp#(Burn)
  346.         if (d > 20) {                //#jp#(Burn)
  347.           BurnSetOnFire(e,self.drone_owner);    //#jp#(Burn)
  348.         }                    //#jp#(Burn)
  349.           }                        //#jp#(Burn)
  350.             }
  351.           }
  352.         }
  353.       }
  354.     }
  355.     e = e.chain;
  356.   }
  357.   
  358.   WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  359.   WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  360.   WriteCoord (MSG_BROADCAST, self.origin_x);
  361.   WriteCoord (MSG_BROADCAST, self.origin_y);
  362.   WriteCoord (MSG_BROADCAST, self.origin_z);
  363.   BecomeExplosion();
  364. };
  365.  
  366. //========================================================================
  367. //   DroneDie
  368. //========================================================================
  369.  
  370. void() DroneDie =
  371. {
  372.   local entity o;
  373.   
  374.   //dprint("DroneDie\n");
  375.   
  376.   o = other;
  377.   other = self;
  378.   self.drone_count = -1; // needed  as trigger in DroneTouch
  379.   DroneTouch();
  380.   other = o;
  381. };
  382.  
  383. //========================================================================
  384. //   DroneThink
  385. //========================================================================
  386.  
  387. void() DroneThink =
  388. {
  389.   local vector x,v;
  390.   local float  have,xn,tvn,vn,tvn,vwn,vmin;
  391.  
  392.   //dprint("DroneThink\n");
  393.   //dprint(ftos(time)); dprint("\n");
  394.  
  395.   if (time > self.drone_sound_time + 0.8) {
  396.     sound (self, CHAN_WEAPON, drone_hoover_sound, 1, ATTN_NORM);
  397.     self.drone_sound_time = time;
  398.   }
  399.   
  400.   if (time > self.ltime + DRONE_LIFETIME + 0.5) {
  401.     self.touch            = SUB_Null;
  402.     self.think            = DroneDie;
  403.     self.nextthink        = time + 0.01;
  404.     self.drone_firstthink = 1;
  405.     return;
  406.   }
  407.   
  408.   if (self.drone_origin_old == self.origin) {
  409.     //dprint("didn't move\n");
  410.     self.velocity_z = 150;
  411.     self.drone_stuck = self.drone_stuck + 1;
  412.     if (self.drone_stuck >= 4) {
  413.       //dprint("stuck, proposing self destruction\n");
  414.       self.ltime = -100;
  415.       self.drone_stuck = 0;
  416.     }
  417.   }
  418.   else self.drone_stuck = 0;
  419.  
  420.   if (self.flags & FL_ONGROUND) self.velocity_z = 150;
  421.   
  422.   self.movetype  = MOVETYPE_FLY;
  423.   self.think     = DroneThink;
  424.   self.nextthink = time + DRONE_THINK_NEXTTIME;
  425.   self.drone_origin_old = self.origin;
  426.   self.flags     = self.flags - (self.flags & FL_ONGROUND);
  427.   
  428.   if (self.drone_bounced) {
  429.     if (time >= self.drone_bounce_time + 0.2) {
  430.       //dprint("resetting size after bouncing\n");
  431.       setsize (self, '-8 -8 -8', '8 8 8');
  432.       self.drone_bounced = 0;
  433.     }
  434.   }
  435.   
  436.   DroneThreat(self.enemy,FALSE);
  437.  
  438.   if (!self.drone_firstthink) {
  439.     setsize (self, '-8 -8 -8', '8 8 8');
  440.     self.drone_firstthink = 1;
  441.     self.owner = self;
  442.     DroneFindTarget(self);
  443.   }
  444.   
  445.   have = 0;
  446.   if (self.drone_target_is_fixed) {
  447.     have = 3;
  448.   }
  449.   else if (self.enemy.deadflag > DEAD_NO) { 
  450.     self.drone_target_is_fixed = 1; 
  451.     have = 3;
  452.   }
  453.   else if (time > self.drone_targeting_time + 2) {
  454.     if (vlen(self.drone_target_vector - self.origin) > 150) have = 1;
  455.   }
  456.   if (!have) {
  457.     if (time > self.drone_targeting_time + 1) {
  458.       if (self.enemy == self.drone_owner) have = 1;
  459.     }
  460.     if (!have) {
  461.       if (time > self.drone_set_target_vector_time + 0.5) have = 2;
  462.     }
  463.   }
  464.   if      (have == 1) have = DroneFindTarget(self);
  465.   else if (have == 2) have = DroneUpdateTargetData(self.enemy,self);
  466.   if (!have) {
  467.     if (vlen(self.drone_target_vector-self.origin) < 40) have = 2;
  468.     else {
  469.       v = self.enemy.origin;
  470.       v_z = v_z + DRONE_TARGET_OFFSET_Z;
  471.       traceline(self.origin, v, TRUE, self);
  472.       if (trace_fraction == 1) have = 2;
  473.     }
  474.     if (have) {
  475.       self.drone_target_vector = self.enemy.origin;
  476.       self.drone_target_vector_z = self.drone_target_vector_z + DRONE_TARGET_OFFSET_Z;
  477.       self.drone_target_velocity = self.enemy.velocity;
  478.     }
  479.   }
  480.   DroneThreat(self.enemy,TRUE);
  481.  
  482.   //dprint("target:"); dprint(self.enemy.classname); dprint(" "); dprint(self.enemy.netname); dprint("\n");
  483.  
  484.   x   = self.drone_target_vector - self.origin;
  485.   xn  = vlen(x);
  486.   x   = normalize(x);
  487.   tvn = vlen(self.drone_target_velocity);
  488.   v   = normalize(self.velocity);
  489.   vn  = vlen(self.velocity);
  490.   vmin = 150;
  491.   
  492.   if (v*x < -0.92) {
  493.     //dprint("randomize\n");
  494.     x   = self.drone_target_vector - self.origin;
  495.     x_x = x_x + 40*(0.5 - random());
  496.     x_y = x_y + 40*(0.5 - random());
  497.     x_z = x_z + 30*random();
  498.     xn  = vlen(x);
  499.     x   = normalize(x);
  500.   }
  501.   
  502.   if (xn < 250)      vwn = tvn+70+(1+v*x)*xn/500*50;
  503.   else if (xn < 500) vwn = 400;
  504.   else               vwn = 600;
  505.   
  506.   if      (vn > vwn)  { vn = vn - 100; if (vn < vmin) vn = vmin; } 
  507.   else if (vn < vwn)  { vn = vn + 100; if (vn > vwn)  vn = vwn;  }
  508.   else if (vn < vmin) { vn = vmin;                               }
  509.   
  510.   self.velocity = self.velocity + x*vn;
  511.   if (self.velocity == '0 0 0') {
  512.     self.velocity = self.velocity + x*(vn+10);
  513.   } else {
  514.     tvn =  vlen(self.velocity);
  515.     if      (tvn > vn)   self.velocity = vn*normalize(self.velocity);
  516.     else if (tvn < vmin) self.velocity = vmin*normalize(self.velocity);
  517.   }
  518. };
  519.  
  520. //========================================================================
  521. //   DroneUpdateTargetData
  522. //========================================================================
  523.  
  524. float(entity targ,entity drone) DroneUpdateTargetData =
  525. {
  526.   local vector v;
  527.  
  528.   //dprint("DroneUpdateTargetData\n");
  529.  
  530.   drone.drone_set_target_vector_time = time;
  531.   v = targ.origin;
  532.   v_z = v_z + DRONE_TARGET_OFFSET_Z;
  533.   traceline(drone.origin, v, TRUE, drone);
  534.   if (trace_fraction != 1) {
  535.     v = v + '20 20 0';
  536.     traceline(drone.origin, v, TRUE, drone);
  537.     if (trace_fraction != 1) {
  538.       v = v + '-40 -40 0';
  539.       traceline(drone.origin, v, TRUE, drone);
  540.       if (trace_fraction != 1) {
  541.     v = v + '0 40 0';
  542.     traceline(drone.origin, v, TRUE, drone);
  543.     if (trace_fraction != 1) {
  544.       v = v + '40 -40 0';
  545.       traceline(drone.origin, v, TRUE, drone);
  546.       if (trace_fraction != 1) {
  547.         return(0);
  548.       }
  549.     }
  550.       }
  551.     }
  552.   }
  553.   drone.enemy = targ;
  554.   drone.drone_target_vector = v;
  555.   drone.drone_target_velocity = targ.velocity;
  556.   return(1);
  557. };
  558.  
  559. //========================================================================
  560. //   DroneFindTarget
  561. //========================================================================
  562.  
  563. float(entity drone) DroneFindTarget =
  564. {
  565.   local entity e, t;
  566.   local vector m_forward;
  567.   local float cos_min,cos;
  568.   
  569.   //dprint("DroneFindTarget\n");
  570.  
  571.   cos_min = -10;
  572.   m_forward = normalize(drone.velocity);
  573.   e = findradius(drone.origin+1000*m_forward,1050);
  574.   while (e) {
  575.     if (e.takedamage == DAMAGE_AIM) {
  576.       if (e.health > 0) {
  577.     if (e.drone_owner != drone.drone_owner || e.classname != "drone") {
  578.       if ((drone.drone_owner.waterlevel < 3 && e.waterlevel < 3)
  579.           || drone.drone_owner.waterlevel == e.waterlevel) {
  580.         cos = normalize(e.origin)*m_forward;
  581.             if (cos > cos_min) {
  582.           if (DroneUpdateTargetData(e,drone)) {
  583.         cos_min = cos;
  584.           }
  585.         }
  586.       }
  587.     }
  588.       }
  589.     }
  590.     e = e.chain;
  591.   }
  592.   drone.drone_targeting_time = time;
  593.   if (cos_min == -1) return(0);
  594.   else return(1);              
  595. };
  596.  
  597.  
  598.  
  599.  
  600.  
  601.